<?php
/**
 *+------------------
 * madong
 *+------------------
 * Copyright (c) https://gitee.com/motion-code  All rights reserved.
 *+------------------
 * Author: Mr. April (405784684@qq.com)
 *+------------------
 * Official Website: http://www.madong.tech
 */

namespace madong\webman\wf\services;

use madong\webman\wf\basic\BaseService;
use madong\helper\Dict;
use madong\ingenious\core\ProcessEngines;
use madong\ingenious\core\ServiceContext;
use madong\ingenious\domain\DefaultNoGenerator;
use madong\ingenious\enums\ProcessConstEnum;
use madong\ingenious\enums\ProcessInstanceStateEnum;
use madong\ingenious\enums\ProcessSubmitTypeEnum;
use madong\ingenious\enums\ProcessTaskStateEnum;
use madong\ingenious\ex\LFlowException;
use madong\ingenious\interface\IExecution;
use madong\ingenious\interface\INoGenerator;
use madong\ingenious\interface\model\IProcessDefine;
use madong\ingenious\interface\model\IProcessInstance;
use madong\ingenious\interface\services\IProcessDefineService;
use madong\ingenious\interface\services\IProcessInstanceService;
use madong\ingenious\libs\utils\ArrayHelper;
use madong\ingenious\libs\utils\AssertHelper;
use madong\ingenious\libs\utils\Expression;
use madong\ingenious\libs\utils\Logger;
use madong\ingenious\libs\utils\Pagination;
use madong\ingenious\libs\utils\ProcessFlowUtils;
use madong\ingenious\libs\utils\PropertyCopier;
use madong\ingenious\model\DecisionModel;
use madong\ingenious\model\EndModel;
use madong\ingenious\model\JoinModel;
use madong\ingenious\model\TaskModel;
use madong\ingenious\processor\handler\MergeBranchHandler;
use madong\interface\IDict;
use madong\webman\wf\dao\ProcessInstanceDao;
use madong\webman\wf\model\virtual\HighLightVirtual;
use madong\ingenious\enums\YourEnum;
use support\Container;

class ProcessInstanceService extends BaseService implements IProcessInstanceService
{

    public function __construct()
    {
        $this->dao = Container::make(ProcessInstanceDao::class);
    }

    public function created(object $param): ?IProcessInstance
    {
        unset($param->id);
        $model = $this->dao->getModel();
        PropertyCopier::copyProperties($param, $model);
        return $model->save();
    }

    public function updated(object $param): bool
    {
        AssertHelper::notNull($param->id ?? '', '参数ID不能为空');
        $model = $this->dao->get($param->id);
        PropertyCopier::copyProperties($param, $model);
        return $model->save();
    }

    public function list(object $param): array
    {
        $where = ArrayHelper::paramsFilter($param, [
            ['parent_id', ''],
            ['process_define_id', ''],
            ['state', ''],
            ['parent_node_name', ''],
            ['business_no', ''],
            ['operator', ''],
            ['display_name', ''],
        ]);
        [$page, $limit] = Pagination::getPageValue($param);
        $items = $this->dao->selectList($where, '*', $page, $limit, 'create_time', ['define' => function ($query) use ($where) {
            $map = ['display_name'];
            foreach ($where as $key => $value) {
                if (in_array($key, $map) && !empty($value)) {
                    $query->where($key, $value);
                }
            }
        }], true)->toArray();
//        $items = $this->dao->selectList($where, '*', $page, $limit, 'create_time', [], true)->toArray();
//        var_dump($items);

        $total = $this->dao->count($where, true);
        foreach ($items as $key => $value) {
            $items[$key]['process_name'] = $value['define']['display_name'] ?? '';
            $items[$key]['ext']          = $value['variable'];
            $items[$key]['form_data']    = ProcessFlowUtils::filterObjectByPrefix((object)$value['variable'], 'f_');
            $items[$key]['variable']     = json_encode($value['variable']);
        }
        return compact('items', 'total');
    }

    public function findById(string|int $id): ?IProcessInstance
    {
        AssertHelper::notNull($id, '参数ID不能为空');
        return $this->dao->get($id, ['*'], ['define']);
    }

    public function finishProcessInstance(string|int $processInstanceId): void
    {
        $model = $this->dao->get($processInstanceId);
        AssertHelper::notNull($model, '实例不存在或被删除');
        $model->set('state', ProcessInstanceStateEnum::FINISHED->value);
        $model->save();
    }

    public function rejectProcessInstance(string|int $processInstanceId): void
    {
        $model = $this->dao->get($processInstanceId);
        AssertHelper::notNull($model, '实例不存在或被删除');
        $model->set('state', ProcessInstanceStateEnum::REJECT->value);
        $model->save();
    }

    public function createProcessInstance(IProcessDefine $processDefine, string $operator, IDict $args, string|null $parentId = '', string|null $parentNodeName = ''): ?IProcessInstance
    {
        $model = $this->dao->getModel();
        $model->set('parent_id', $parentId);
        $model->set('parent_node_name', $parentNodeName);
        $model->set('process_define_id', $processDefine->getData('id'));
        $model->set('operator', $operator);
        $model->set('state', ProcessInstanceStateEnum::DOING->value);
        // 业务流水号从流程变量中获取
        $model->set('business_no', $args->{ProcessConstEnum::BUSINESS_NO->value} ?? '');
        if (empty($args->get(ProcessConstEnum::BUSINESS_NO->value))) {
            //外面没有传单据编号使用内置默认编号生成器
            $defaultNoGenerator = ServiceContext::find(INoGenerator::class) ?? new DefaultNoGenerator();
            $model->set('business_no', $defaultNoGenerator->generate(null));
        }
        //添加期望时间
        $processDefineService = ServiceContext::find(IProcessDefineService::class);

        $processModel = $processDefineService->processDefineToModel($processDefine);
        $expireTime   = $processModel->getExpireTime();
        if (!empty($expireTime)) {
            $dateTime = ProcessFlowUtils::processTime($expireTime, $args);
            if ($dateTime !== null) {
                $model->set('expire_time', $dateTime->getTimestamp());
            }
        }

        // 追加用户信息到参数
        ProcessFlowUtils::addUserInfoToArgs($operator, $args);


        // 追加自动构造标题
        ProcessFlowUtils::addAutoGenTitle($processDefine->getData('display_name'), $args);
        $model->set('variable', json_encode($args->toArray()));
        return $this->saveProcessInstance($model);
    }

    public function addVariable(string|int $processInstanceId, IDict $args): void
    {
        $model = $this->dao->get($processInstanceId);
        AssertHelper::notNull($model, '流程实例不存在');
        $variable = $model->getData('variable') ?? (object)[];
        $newDict  = ProcessFlowUtils::variableToDict($variable);
        $newDict->putAll($args->getAll());
        $model->set('variable', json_encode($newDict->getAll()));
        $model->save();
    }

    public function removeVariable(string|int $processInstanceId, string|array $keys): void
    {
        $model = $this->get($processInstanceId);
        AssertHelper::notNull($model, '流程实例不存在');
        $variable = $model->getData('variable') ?? (object)[];
        $oldDict  = new Dict();
        $oldDict->putAll($variable);
        foreach (is_array($keys) ? $keys : explode(',', $keys) as $value) {
            $oldDict->remove($value);
        }
        $model->set('variable', $oldDict->getAll());
        $model->save();
    }

    public function saveProcessInstance(IProcessInstance $processInstance): ?IProcessInstance
    {
        $processInstance->set('create_time', time());
        $processInstance->set('update_time', time());
        return $this->dao->save($processInstance->toArray());
    }

    public function interrupt(string|int $processInstanceId, string|int $operator): void
    {
        // 1. 将该流程实例产生的任务状态修改为终止
        $processTaskService = new ProcessTaskService();
        $map1               = [
            'id'         => $processInstanceId,
            'task_state' => ProcessTaskStateEnum::DOING->value,
        ];
        $processTask        = $processTaskService->dao->get($map1);
        if (!empty($processTask)) {
            $processTask->set('task_state', ProcessTaskStateEnum::INTERRUPT->value);
            $processTask->set('update_time', time());
            $processTask->set('update_user', $operator);
            $processTask->save();
        }
        // 2. 将该流程实例状态修改为终止
        $map2            = [
            'id'    => $processInstanceId,
            'state' => ProcessInstanceStateEnum::DOING->value,
        ];
        $processInstance = $this->get($map2);
        if (!empty($processInstance)) {
            $processInstance->set('state', ProcessInstanceStateEnum::INTERRUPT->value);
            $processInstance->set('update_time', time());
            $processInstance->set('update_user', $operator);
            $processInstance->save();
        }
    }

    public function resume(string|int $processInstanceId, string|int $operator): void
    {
        // 1. 更新流程实例状态为进行中
        $model = $this->dao->get($processInstanceId);
        AssertHelper::notNull($model, '唤醒失败，流程实例不存在');
        $model->set('state', ProcessInstanceStateEnum::DOING);
        $model->set('update_time', time());
        $model->set('update_user', $operator);
        $model->save();
        // 2.被终止的任务状态修改为进行中
        $processTaskService = new ProcessTaskService();
        $map1               = [
            'process_instance_id' => $processInstanceId,
            'task_state'          => ProcessTaskStateEnum::INTERRUPT->value,
        ];
        $taskModel          = $processTaskService->dao->get($map1);
        AssertHelper::notNull($taskModel, '唤醒失败，查找终止任务失败');
        $taskModel->set('task_state', ProcessTaskStateEnum::DOING->value);
        $model->set('update_time', time());
        $model->set('update_user', $operator);
        $model->save();
    }

    public function cascadeDelete(string|int|array $processInstanceId, string|null|int $operator = null): array
    {
        // 1. 将该流程实例状态修改为撤回
        return $this->transaction(function () use ($processInstanceId, $operator) {
            $data       = ArrayHelper::normalize($processInstanceId);
            $deletedIds = [];
            foreach ($data as $id) {
                $state = [ProcessInstanceStateEnum::DOING->value, ProcessInstanceStateEnum::PENDING->value, ProcessInstanceStateEnum::FINISHED->value];
                $model = $this->dao->getModel()->where('id', $id)->whereNotIn('state', $state)->first();
                AssertHelper::notNull($model, '流程实例不存在或已完成，撤回失败');
                if ($model != null) {
                    //1.删除task
                    $map1               = ['process_instance_id' => $model->getData('id')];
                    $processTaskService = new ProcessTaskService();
                    $taskList           = $processTaskService->dao->selectList($map1, '*', 0, 0, '', [], true);
                    //2.删除actions
                    foreach ($taskList as $task) {
                        $map2                    = ['process_task_id' => $task->getData('id')];
                        $processTaskActorService = new ProcessTaskActorService();
                        $actorList               = $processTaskActorService->selectList($map2, '*', 0, 0, '', [], true);
                        foreach ($actorList as $actor) {
                            $actor->delete();
                        }
                        $task->delete();
                    }
                    //3.移除历史记录
                    $processTaskHistoryService = new ProcessTaskHistoryService();
                    $taskHistoryList           = $processTaskHistoryService->dao->selectList($map1, '*', 0, 0, '', [], true);
                    foreach ($taskHistoryList as $task) {
                        $map2                    = ['process_task_id' => $task->getData('id')];
                        $processTaskActorService = new ProcessTaskActorHistoryService();
                        $actorList               = $processTaskActorService->selectList($map2, '*', 0, 0, '', [], true);
                        foreach ($actorList as $actor) {
                            $actor->delete();
                        }
                        $task->delete();
                    }
                }
                $model->delete();
                $primaryKey   = $model->getPk();
                $deletedIds[] = $model->{$primaryKey};
            }
            return $deletedIds ?? [];
        });
    }

    public function pending(string|int $processInstanceId, string|int $operator): void
    {
        // 1. 将该流程实例产生的任务状态修改为挂起
        $processTaskService = new ProcessTaskService();
        $map1               = [
            'process_instance_id' => $processInstanceId,
            'task_state'          => ProcessTaskStateEnum::DOING->value,
        ];
        $taskModel          = $processTaskService->dao->get($map1);
        AssertHelper::notNull($taskModel, '挂起失败，没有进行中的任务');
        $taskModel->set('task_state', ProcessTaskStateEnum::PENDING->value);
        $taskModel->set('update_time', time());
        $taskModel->set('update_user', $operator);
        $taskModel->save();
        // 2. 将该流程实例状态修改为挂起
        $map2  = [
            'id'    => $processInstanceId,
            'state' => ProcessInstanceStateEnum::DOING->value,
        ];
        $model = $this->dao->get($map2);
        AssertHelper::notNull($model, '挂起失败，流程实例不存在');
        $model->set('state', ProcessInstanceStateEnum::PENDING->value);
        $model->set('update_time', time());
        $model->set('update_user', $operator);
        $model->save();
    }

    public function activate(string|int $processInstanceId, string|int $operator): void
    {
        // 1. 更新流程实例状态为进行中
        $model = $this->dao->get($processInstanceId);
        AssertHelper::notNull($model, '激活失败，流程实例不存在');
        $model->set('state', ProcessInstanceStateEnum::PENDING->value);
        $model->set('update_time', time());
        $model->set('update_user', $operator);
        $model->save();
        // 2.被终止的任务状态修改为进行中
        $processTaskService = new ProcessTaskService();
        $map1               = [
            'process_instance_id' => $processInstanceId,
            'task_state'          => ProcessTaskStateEnum::INTERRUPT->value,
        ];
        $taskModel          = $processTaskService->dao->get($map1);
        AssertHelper::notNull($taskModel, '挂起失败，没有进行中的任务');
        $taskModel->set('task_state', ProcessTaskStateEnum::DOING->value);
        $taskModel->set('update_time', time());
        $taskModel->set('update_user', $operator);
        $taskModel->save();
    }

    public function updateProcessInstance(IProcessInstance $processInstance): void
    {
        $processInstance->set('update_time', time());
        $processInstance->save();
    }

    public function getById(string $id): ?IProcessInstance
    {
        return $this->dao->get($id);
    }

    public function startAndExecute(string|int $processDefineId, IDict $args): ?IProcessInstance
    {
        $configuration = ServiceContext::getBackupConfig();
        if (empty($configuration)) {
            throw new LFlowException('没有找到上下文引擎配置');
        }
        $operator        = $args->get(ProcessConstEnum::USER_USER_ID->value);
        $engines         = new ProcessEngines($configuration);

        $processInstance = $engines->startProcessInstanceById($processDefineId, $operator, $args);

        //获取进行中的任务
        $processTaskList = $engines->processTaskService()->getDoingTaskList($processInstance->getData('id'), '');

        // 取任务自动执行
        foreach ($processTaskList as $processTask) {
            $args->put(ProcessConstEnum::SUBMIT_TYPE->value, ProcessSubmitTypeEnum::APPLY->value);
            $engines->executeProcessTask($processTask->getData('id'), ProcessConstEnum::AUTO_ID->value, $args);
        }
        return $processInstance;
    }

    public function highLight(string|int $processInstanceId): array
    {
        $vo            = new HighLightVirtual();
        $configuration = ServiceContext::getBackupConfig();
        if (empty($configuration)) {
            //如果没有从配置获取
            $configuration = config('ingenious');
        }
        if (empty($configuration)) {
            throw new LFlowException('没有找到上下文引擎配置');
        }

        $model          = $this->findById($processInstanceId);
        $processEngines = new ProcessEngines($configuration);
        Logger::debug('highLight 开始【process_instance_id=' . $processInstanceId . '】');
        if ($model != null) {
            Logger::debug('highLight 【process_instance_id=' . $processInstanceId . ' 拿到正在进行中的任务活跃节点】');
            $processModel = $processEngines->processDefineService()->getProcessModel($model->getData('process_define_id'));
            // 拿到正在进行中的任务==>活跃节点
            $processTaskList = $processEngines->processTaskService()->getDoingTaskList($processInstanceId, '');//进行中的
            $finishTasksList = $processEngines->processTaskHistoryService()->getDoneTaskList($processInstanceId, '');//已完成的
            foreach ($processTaskList as $task) {
                if (!$vo->contains('active_node_names', $task->getData('task_name'))) {
                    $vo->add('active_node_names', $task->getData('task_name'));
                    $this->recursionModel($processModel->getStart(), $model, $processTaskList, $finishTasksList, $task->getData('task_name'), $vo);
                }
            }

            // 拿到非正常结束的流程实例状态值
            $filteredEnums = array_filter(ProcessInstanceStateEnum::all(), function ($enum) {
                $inProgressCode = ProcessInstanceStateEnum::getValueByLabel('进行中');
                $completedCode  = ProcessInstanceStateEnum::getValueByLabel('已完成');
                return $enum->value != $inProgressCode && $enum->value != $completedCode;
            });

            $orderStatusList = array_map(function ($enum) {
                return $enum->value;
            }, $filteredEnums);

            //非正常结束特殊处理
            if (in_array($model->getData('state'), $orderStatusList)) {
                Logger::debug('highLight 非正常结束特殊处理【process_instance_id=' . $processInstanceId . ' 】');
                $hisProcessTaskList = $processEngines->processTaskHistoryService()->getDoneTaskList($processInstanceId, '');
                if (!empty($hisProcessTaskList)) {
                    $lastProcessTask = $hisProcessTaskList[count($hisProcessTaskList) - 1];
                    $nodeModel       = $processModel->getNode($lastProcessTask->getData('task_name'));
                    Logger::debug('highLight 非正常结束处理开始递归');
                    $this->recursionModel($processModel->getStart(), $model, $hisProcessTaskList, $finishTasksList, $nodeModel->getOutputs()[0]->getTo(), $vo);
                }
            } else {
                Logger::debug('highLight 其他特殊处理【process_instance_id=' . $processInstanceId . ' 】');
                $endModels = $processModel->getModels(EndModel::class);
                foreach ($endModels as $endModel) {
                    $this->recursionModel($processModel->getStart(), $model, $processTaskList, $finishTasksList, $endModel->getName(), $vo);
                }
            }
        }
        Logger::debug('highLight 结束【process_instance_id=' . $processInstanceId . '】');
        return $vo->toArray();
    }

public function calculateTimeDifference($startTimestamp, $endTimestamp): string
{
    // 确保开始时间小于结束时间
    if ($startTimestamp > $endTimestamp) {
        return "结束时间必须大于开始时间";
    }

    // 计算时间差
    $diffInSeconds = $endTimestamp - $startTimestamp;

    // 计算各个时间单位
    $years = floor($diffInSeconds / (365 * 24 * 60 * 60));
    $diffInSeconds -= $years * (365 * 24 * 60 * 60);

    $months = floor($diffInSeconds / (30 * 24 * 60 * 60));
    $diffInSeconds -= $months * (30 * 24 * 60 * 60);

    $days = floor($diffInSeconds / (24 * 60 * 60));
    $diffInSeconds -= $days * (24 * 60 * 60);

    $hours = floor($diffInSeconds / (60 * 60));
    $diffInSeconds -= $hours * (60 * 60);

    $minutes = floor($diffInSeconds / 60);
    $seconds = $diffInSeconds % 60;

    // 构建输出字符串
    $result = [];
    if ($years > 0) {
        $result[] = "{$years}年";
    }
    if ($months > 0) {
        $result[] = "{$months}月";
    }
    if ($days > 0) {
        $result[] = "{$days}天";
    }
    if ($hours > 0) {
        $result[] = "{$hours}小时";
    }
    if ($minutes > 0) {
        $result[] = "{$minutes}分钟";
    }
    if ($seconds > 0 || empty($result)) { // 如果没有其他单位，显示秒
        $result[] = "{$seconds}秒";
    }

    return implode(' ', $result);
}


    public function approvalRecord(string|int $processInstanceId): array
    {
        $processTaskService = new ProcessTaskHistoryService();
        $map1               = [
            'process_instance_id' => $processInstanceId,
            'not_in_task_state'   => implode(',', [ProcessTaskStateEnum::DOING->value, ProcessTaskStateEnum::WITHDRAW->value, ProcessTaskStateEnum::ABANDON->value]),//不包括“进行中 已撤回 已废弃” 任务
        ];
        $processTaskList    = $processTaskService->dao->selectList($map1, '*', 0, 0, 'finish_time asc', [], true);
        if ($processTaskList == null) {
            return [];
        }
        foreach ($processTaskList as $task) {
            $startTimestamp = $task->getData('create_time');
            $endTimestamp   = $task->getData('finish_time');
            if (!empty($endTimestamp)) {
                $task->time_taken = $this->calculateTimeDifference($startTimestamp, $endTimestamp);
            }
        }
        return $processTaskList->toArray();
    }

    public function withdraw(string|int|array $processInstanceId, string|int $operator): void
    {
        $this->transaction(function () use ($processInstanceId, $operator) {
            $data = ArrayHelper::normalize($processInstanceId);
            foreach ($data as $id) {
                // 1. 将该流程实例状态修改为撤回
                $map1            = [
                    'id'    => $id,
                    'state' => ProcessInstanceStateEnum::DOING->value,
                ];
                $processInstance = $this->dao->get($map1);
                AssertHelper::notNull($processInstance, $id . '流程实例不存在或已完成，撤回失败');
                $processInstance->set('state', ProcessInstanceStateEnum::WITHDRAW->value);
                $processInstance->set('update_time', time());
                $processInstance->set('update_user', $operator);
                if ($processInstance->save()) {
                    // 2. 将该流程实例产生的任务状态修改为撤回
                    $processTaskService = new ProcessTaskService();
                    $map2               = [
                        'process_instance_id' => $id,
                        'task_state'          => ProcessTaskStateEnum::DOING->value,
                    ];
                    $upData             = [
                        'task_state'  => ProcessTaskStateEnum::WITHDRAW->value,
                        'update_time' => time(),
                        'update_by'   => $operator,
                    ];
                    $processTaskService->dao->update($map2, $upData);
                }
            }
        });
    }

    public function updateCountersignVariable(TaskModel $taskModel, IExecution $execution, array $taskActors): void
    {
        /**
         * ● nrOfActivateInstances：当前活动的实例数量，即还没有完成的实例数量
         * ● loopCounter ：循环计数器，办理人在列表中的索引
         * ● nrOfInstances：会签中总共的实例数
         * ● nrOfCompletedInstances：已经完成的实例数量
         * ● operatorList：会签办理人列表
         */
        // 会签任务变量前缀
        $prefix      = ProcessConstEnum::COUNTERSIGN_VARIABLE_PREFIX->value . $taskModel->getName() . "_";
        $addVariable = new Dict();
        // 更新会签总实例数，nrOfInstances
        $addVariable->put($prefix . ProcessConstEnum::NR_OF_INSTANCES->value, count($taskActors));
        // 更新会签当前活动实例数，nrOfActivateInstances
        $addVariable->put($prefix . ProcessConstEnum::NR_OF_ACTIVATE_INSTANCES->value, count($execution->getDoingTaskList()));
        // 更新会签已完成的实例数，nrOfCompletedInstances
        $addVariable->put($prefix . ProcessConstEnum::NR_OF_COMPLETED_INSTANCES->value, $execution->getArgs()->get($prefix . ProcessConstEnum::NR_OF_COMPLETED_INSTANCES));
        // 更新会签操作人列表 countersignOperatorList
        $addVariable->put($prefix . ProcessConstEnum::COUNTERSIGN_OPERATOR_LIST->value, $taskActors);
        $this->addVariable($execution->getProcessInstanceId(), $addVariable);
    }

    public function createCCInstance(string|int $processInstanceId, string|int $creator, string|int $actorIds): void
    {
        foreach (explode(',', $actorIds) as $actorId) {
            // 查询数据库中是否存在具有相同流程实例ID和演员ID的记录
            $processCcInstanceService = new ProcessCcInstanceService();
            $count                    = $processCcInstanceService->dao->count(['process_instance_id' => $processInstanceId, 'actor_id' => $actorId], true);
            // 如果不存在记录（count为0）
            if ($count === 0) {
                // 创建新的 ProcessCcInstance 实例
                $processInstanceService = ServiceContext::find(IProcessInstanceService::class);
                $model                  = $processInstanceService->dao->getModel();
                $model->set('process_instance_id', $processInstanceId);
                $model->set('actor_id', $actorId);
                $model->set('state', YourEnum::NO->value); // 假设 YourEnumClass 是枚举类，且有一个 NO 常量
                $model->set('create_user', $creator);
                $model->set('create_time', time());
                $model->set('update_user', $creator);
                $model->set('update_time', time());
                $model->save();
            }
        }
    }

    public function updateCCStatus(string|int $processInstanceId, string|int $actorId): void
    {
        AssertHelper::notNull($processInstanceId, '参数 process_instance_id 不能为空');
        AssertHelper::notNull($actorId, '参数 actor_id 不能为空');
        $processCcInstanceService = new ProcessCcInstanceService();
        $map1                     = [
            'process_instance_id' => $processInstanceId,
            'actor_id'            => $actorId,
        ];
        $processCcInstance        = $processCcInstanceService->dao->get($map1);
        AssertHelper::notNull($processCcInstance, '操作异常请刷新后重试');
        $processCcInstance->set('state', YourEnum::YES->value);
        $processCcInstance->set('update_time', time());
        $processCcInstance->set('update_user', $actorId);
        $processCcInstance->save();
    }

    public function ccInstancePage(object $param): array
    {
        $param->state             = YourEnum::NO;
        $processCcInstanceService = new ProcessCcInstanceService();
        return $processCcInstanceService->list($param);
    }

    private function recursionModel($nodeModel, $processInstance, $processTaskList, $finishTasksList, $taskName, $vo): void
    {
        if ($nodeModel->getName() === $taskName) {
            if ($nodeModel instanceof EndModel) {
                $vo->add('history_node_names', $nodeModel->getName());
            }
            return;
        }

        if (!$vo->contains('history_node_names', $nodeModel->getName())) {
            $vo->add('history_node_names', $nodeModel->getName());
            $filteredOutputs = array_filter($nodeModel->getOutputs(), function ($output) use ($nodeModel, $processInstance, $processTaskList, $finishTasksList, $vo) {
                $defaultDecisionInputModel = null;
                $historyTask               = null;
                if ($nodeModel instanceof DecisionModel) {
                    Logger::debug('highLight DecisionModel 决策表达式处理');
                    $defaultDecisionInputModel = $nodeModel->getInputs()[0]->getSource();
                    // 使用查询构建器对模型对象列表进行过0
                    $filteredTasks = [];
                    foreach ($processTaskList as $hisTask) {
                        if ($defaultDecisionInputModel->getName() === $hisTask->getData('task_name')) {
                            $filteredTasks[] = $hisTask;
                        }
                    }
                    $historyTask = reset($filteredTasks); // 获取筛选后的第一个元素
                }

                $args = new Dict();
                $args->putAll(json_decode($processInstance->getData('variable'), true));
                if ($historyTask) {
                    $args->putAll(json_decode($historyTask->getData('variable')));
                }
                if (!empty($output->getExpr()) && $nodeModel instanceof DecisionModel && $defaultDecisionInputModel !== null) {
                    //表达式处理
                    return Expression::eval($output->getExpr(), $args);
                }
                if ($nodeModel instanceof DecisionModel) {
                    $expr = $nodeModel->getExpr();
                    if (!empty($expr)) {
                        return true;
                    }
                }

                //合并节点处理
                if ($nodeModel instanceof JoinModel) {
                    Logger::debug('highLight JoinModel 合并节点处理');
                    $isMerged = MergeBranchHandler::isMerged($processInstance->getData('id'), $nodeModel);
                    if (!$isMerged) {
                        //未能合并，要把已加入历史的节点和边删除
                        $vo->remove('history_node_names', $nodeModel->getName());
                        foreach ($nodeModel->getInputs() as $input) {
                            $vo->remove('history_edge_names', $input->getName());
                        }
                    }
                    return $isMerged;
                }
                return true;
            });

            // 对过滤后的结果进行遍历操作
            foreach ($filteredOutputs as $transitionModel) {
                if (!$vo->contains('history_edge_names', $transitionModel->getName())) {
                    $vo->add('history_edge_names', $transitionModel->getName());
                    $this->recursionModel($transitionModel->getTarget(), $processInstance, $processTaskList, $finishTasksList, $taskName, $vo);
                }
            }
        }
    }
}
